#pragma once

#include <iostream>
#include <set>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/epoll.h>
#include "include/Log.hpp"

const static int default_epoll_create_size = 128;

class Epoller
{
public:
    Epoller(): _epfd(-1)
    {
        _epfd = ::epoll_create(default_epoll_create_size);
        if(_epfd == -1)
        {
            log.message(FATAL, "epoll create error... %d:%s", errno, strerror(errno));
            exit(1);
        }
        log.message(INFO, "epoll create success, epfd: %d", _epfd);
    }

    void addEvent(int fd, uint32_t events)
    {
        struct epoll_event ev;
        ev.events = events;
        ev.data.fd = fd;
        
        int n = ::epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &ev);
        if(n < 0)
        {
            log.message(ERROR, "epoll ctl add error... %d: %s", errno, strerror(errno));
        }

        _fdSet.insert(fd);
    }

    void deletEvent(int sockfd)
    {
        int n = ::epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr);
        if(n < 0)
        {
            log.message(ERROR, "epoll ctl delete error... %d: %s", errno, strerror(errno));
        }

        _fdSet.erase(sockfd);
    }

    void modifyEvent(int sockfd, uint32_t events)
    {
        struct epoll_event ev;
        ev.events = events;
        ev.data.fd = sockfd;
        int n = ::epoll_ctl(_epfd, EPOLL_CTL_MOD, sockfd, &ev);
        if(n < 0)
        {
            log.message(ERROR, "epoll ctl modify error... %d: %s", errno, strerror(errno));  
        }
    }

    int wait(struct epoll_event* revs, int maxevents, int timeout)
    {
        return ::epoll_wait(_epfd, revs, maxevents, timeout);
    }

    void printFdList()
    {
        std::cout << "fds: ";
        for (auto &fd : _fdSet)
        {
            std::cout << fd << " ";
        }
        std::cout << std::endl;
    }

    ~Epoller()
    {
        if(_epfd >= 0)
        {
            close(_epfd);
        }
        log.message(INFO, "epoll close success...");
    }
private:
    int _epfd;
    std::set<int> _fdSet;
};